package mspbots.cw.business.core.companies;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.cw.business.core.BaseReceiver;
import mspbots.cw.business.core.contacts.Contacts;
import mspbots.cw.business.core.contacts.ContactsRepository;
import mspbots.cw.business.core.subdata.SubdataRepository;
import mspbots.cw.common.ResultMsg;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.util.Iterator;
import java.util.List;

/**
 * @author Jay.Yang
 */
@Log4j2
@Component
@RequiredArgsConstructor
public class CompaniesReceiver extends BaseReceiver {

    private final CompaniesRepository companiesRepository;
    private final ContactsRepository contactsRepository;
    private final SubdataRepository subdataRepository;

    @RabbitListener(queues = "connect-wise.companies.tl")
    public void process(ResultMsg resultMsg) {
        JsonNode entity = resultMsg.getEntity();
        Company data = super.objectMapper.convertValue(entity, Company.class);
        data.setId(null);
        data.setCompanyId(resultMsg.getId());
        data.setTenantCode(resultMsg.getTenantId());
        data.setSyncTime(resultMsg.getSyncDate());

        data.setStatusName(super.getStringValueName(entity.get("status")));
        data.setLastUpdated(super.getDateTimeValue(entity.findValue("lastUpdated")));
        data.setDateEntered(super.getDateTimeValue(entity.findValue("dateEntered")));
        data.setCountryId(super.getLongValueId(entity.get("country")));
        data.setCountryName(super.getStringValueName(entity.get("country")));
        data.setTaxCodeId(super.getLongValueId(entity.get("taxCode")));
        data.setTaxCodeName(super.getStringValueName(entity.get("taxCode")));
        data.setTerritoryId(super.getLongValueId(entity.get("territory")));
        data.setTerritoryName(super.getStringValueName(entity.get("territory")));
        data.setBillingSiteId(super.getLongValueId(entity.get("billingSite")));
        data.setBillingSiteName(super.getStringValueName(entity.get("billingSite")));
        data.setBillingTermsId(super.getLongValueId(entity.get("billingTerms")));
        data.setBillingTermsName(super.getStringValueName(entity.get("billingTerms")));
        data.setBillToCompanyId(super.getLongValueId(entity.get("billToCompany")));
        data.setBillToCompanyName(super.getStringValueName(entity.get("billToCompany")));
        data.setTimeZoneSetupId(super.getLongValueId(entity.get("timeZoneSetup")));
        data.setTimeZoneSetupName(super.getStringValueName(entity.get("timeZoneSetup")));
        data.setBillingContactId(super.getLongValueId(entity.get("billingContact")));
        data.setBillingContactName(super.getStringValueName(entity.get("billingContact")));
        data.setDefaultContactId(super.getLongValueId(entity.get("defaultContact")));
        data.setDefaultContactName(super.getStringValueName(entity.get("defaultContact")));
        data.setTerritoryManagerId(super.getLongValueId(entity.get("territoryManager")));
        data.setTerritoryManagerName(super.getStringValueName(entity.get("territoryManager")));
        data.setInvoiceDeliveryMethodId(super.getLongValueId(entity.get("invoiceDeliveryMethod")));
        data.setInvoiceDeliveryMethodName(super.getStringValueName(entity.get("invoiceDeliveryMethod")));
        data.setCompanyEntityTypeName(super.getStringValueName(entity.get("companyEntityType")));
        data.setUpdatedBy(super.getStringValue(entity.findValue("updatedBy")));
        data.setMarketName(super.getStringValueName(entity.get("market")));
        data.setCurrencyName(super.getStringValueName(entity.get("currency")));
        data.setParentCompanyName(super.getStringValueName(entity.get("parentCompany")));


        if (!ObjectUtils.isEmpty(entity.get("teams"))) {
            StringBuilder names = new StringBuilder();
            StringBuilder ids = new StringBuilder();
            Iterator<JsonNode> nodeJson = entity.get("teams").elements();
            while (nodeJson.hasNext()) {
                JsonNode teamsNode = nodeJson.next();
                if (!ObjectUtils.isEmpty(teamsNode.get("teamRole")) && !ObjectUtils.isEmpty(teamsNode.get("member"))) {
                    names.append(", ").append(super.getStringValueName(teamsNode.get("teamRole"))).append(": ")
                            .append(super.getStringValueName(teamsNode.get("member")));
                    ids.append(", ").append(super.getStringValueName(teamsNode.get("teamRole"))).append(": ")
                            .append(super.getLongValueId(teamsNode.get("member")));
                }
            }
            data.setCompanyTeamNames(names.indexOf(",") == -1 ? "" : names.substring(2));
            data.setCompanyTeamIds(ids.indexOf(",") == -1 ? "" : ids.substring(2));
        }

        List<Contacts> contactList = this.contactsRepository
                .findByCompanyIdAndDefaultFlagAndTenantCode(resultMsg.getId(), true, resultMsg.getTenantId())
                .collectList().block(Duration.ofSeconds(10));

        if (!CollectionUtils.isEmpty(contactList)) {
            StringBuilder names = new StringBuilder();
            StringBuilder emails = new StringBuilder();
            for (Contacts con : contactList) {
                String firstName = StringUtils.isEmpty(con.getFirstName()) ? "" : con.getFirstName();
                String lastName = StringUtils.isEmpty(con.getLastName()) ? "" : con.getLastName();
                names.append(", ").append(firstName).append(" ").append(lastName);
                emails.append(", ").append(con.getEmail());
            }
            data.setContactNames(names.indexOf(",") == -1 ? "" : names.substring(2));
            data.setContactEmails(emails.indexOf(",") == -1 ? "" : ("null".equals(emails.substring(2)) ? "" : emails.substring(2)));
        }
        if (!ObjectUtils.isEmpty(entity.get("types"))) {
            Iterator<JsonNode> nodeJson = entity.get("types").elements();
            while (nodeJson.hasNext()) {
                JsonNode next = nodeJson.next();
                String id = super.getStringValue(next.get("id"));
                String name = super.getStringValue(next.get("name"));
                data.setCompanyTypeIds(ObjectUtils.isEmpty(data.getCompanyTypeIds()) ? id : data.getCompanyTypeIds() + ", " + id);
                data.setCompanyTypeNames(ObjectUtils.isEmpty(data.getCompanyTypeNames()) ? name : data.getCompanyTypeNames() + ", " + name);
            }
        } else if (!ObjectUtils.isEmpty(entity.get("typeIds"))) {
            Iterator<JsonNode> nodeJson = entity.get("typeIds").elements();
            while (nodeJson.hasNext()) {
                Long typeId = nodeJson.next().asLong();
                data.setCompanyTypeIds(ObjectUtils.isEmpty(data.getCompanyTypeIds()) ? typeId.toString() : data.getCompanyTypeIds() + ", " + typeId);
                subdataRepository.findByCwIdAndApiTypeAndTenantCode(typeId, "COMPANY-TYPES", resultMsg.getTenantId())
                        .map(result -> {
                            data.setCompanyTypeNames(ObjectUtils.isEmpty(data.getCompanyTypeNames()) ? result.getName() : data.getCompanyTypeNames() + ", " + result.getName());
                            return data;
                        }).block(Duration.ofSeconds(10));
            }
        }

        this.companiesRepository.findByCompanyIdAndTenantCode(resultMsg.getId(), resultMsg.getTenantId())
                .map(result -> {
                    data.setId(result.getId());
                    return data;
                })
                .defaultIfEmpty(data)
                .flatMap(this.companiesRepository::save).block(Duration.ofSeconds(10));
    }
}
